// AnimateWrapper.js - HOC utility for adding motion animations to any component
// Import this file once in your layout or shared component file
import React, { useEffect, useState, cloneElement, Children } from 'react';
import { motion } from 'framer-motion';

// The main HOC - wrap any component with this to add animations
const AnimateWrapper = ({
  children,
  // Animation trigger options
  inView = true, // Whether to animate when in viewport
  threshold = 0.5, // How much of component needs to be visible (0-1)
  once = true, // Only animate once or every time it enters viewport
  
  // Animation effects (all optional with sensible defaults)
  fade = true, // Fade in effect
  slide = false, // Slide up effect
  scale = false, // Scale effect
  blur = false, // Blur effect
  rotate = false, // Rotation effect
  
  // Animation customization
  duration = 0.5, // Animation duration in seconds
  delay = 0, // Delay before animation starts
  stagger = 0, // Stagger children animations
  
  // Interaction animations
  hover = false, // Add hover animations
  tap = false, // Add tap/click animations
  
  // Pass through any other props
  ...props
}) => {
  const [ref, setRef] = useState(null);
  const [isVisible, setIsVisible] = useState(!inView); // Start visible if not using inView

  // Set up intersection observer to detect when element is in viewport
  useEffect(() => {
    if (!ref || !inView) return;
    
    const observer = new IntersectionObserver(
      ([entry]) => {
        // Update visibility state when intersection changes
        if (entry.isIntersecting) {
          setIsVisible(true);
          // If only animating once, disconnect after becoming visible
          if (once) observer.disconnect();
        } else if (!once) {
          setIsVisible(false);
        }
      },
      { threshold }
    );
    
    observer.observe(ref);
    return () => observer.disconnect();
  }, [ref, inView, once, threshold]);

  // Build animation variants based on props
  const variants = {
    hidden: {
      opacity: fade ? 0 : 1,
      y: slide ? 50 : 0,
      scale: scale ? 0.8 : 1,
      filter: blur ? 'blur(10px)' : 'blur(0px)',
      rotate: rotate ? -5 : 0,
    },
    visible: {
      opacity: 1,
      y: 0,
      scale: 1,
      filter: 'blur(0px)',
      rotate: 0,
    }
  };
  
  // Build hover animations if enabled
  const hoverEffects = hover ? {
    whileHover: {
      scale: scale ? 1.05 : 1,
      y: slide ? -5 : 0,
      filter: blur ? 'blur(0px)' : undefined,
    }
  } : {};
  
  // Build tap animations if enabled
  const tapEffects = tap ? {
    whileTap: {
      scale: scale ? 0.95 : 1,
    }
  } : {};

  // Handle case with no children
  if (!children) {
    // If no children, use a motion div as fallback
    const MotionDiv = motion.div;
    
    return (
      <MotionDiv
        ref={setRef}
        initial="hidden"
        animate={isVisible ? "visible" : "hidden"}
        variants={variants}
        transition={{ 
          duration, 
          delay,
          stagger: stagger ? { each: stagger } : undefined 
        }}
        {...hoverEffects}
        {...tapEffects}
        {...props}
      />
    );
  }

  // For a single child or multiple children
  const childArray = Children.toArray(children);
  
  // If stagger is enabled, wrap each child in its own motion component
  if (stagger && childArray.length > 1) {
    return (
      <motion.div
        ref={setRef}
        initial="hidden"
        animate={isVisible ? "visible" : "hidden"}
        variants={{
          hidden: {},
          visible: {
            transition: {
              staggerChildren: stagger
            }
          }
        }}
        {...props}
      >
        {childArray.map((child, index) => {
          // Create a motion version of the child element
          const MotionChild = motion(child.type);
          
          return (
            <MotionChild
              key={index}
              {...child.props}
              variants={variants}
              transition={{ duration }}
              {...hoverEffects}
              {...tapEffects}
            />
          );
        })}
      </motion.div>
    );
  }
  
  // For a single child (the common case), we can just get its type
  const child = childArray[0];
  
  // Create a motion version of the component
  const MotionComponent = motion(child.type);
  
  // Clone the child with motion props
  return cloneElement(
    <MotionComponent
      ref={setRef}
      initial="hidden"
      animate={isVisible ? "visible" : "hidden"}
      variants={variants}
      transition={{ duration, delay }}
      {...hoverEffects}
      {...tapEffects}
      {...child.props}
      {...props}
    />,
    {},
    child.props.children
  );
};

export default AnimateWrapper;

// EXAMPLES:

// Example 1: Basic usage with MUI Button
// import AnimateWrapper from './AnimateWrapper';
// import Button from '@mui/material/Button';
//
// function MyComponent() {
//   return (
//     <AnimateWrapper fade slide hover>
//       <Button variant="contained">Click me</Button>
//     </AnimateWrapper>
//   );
// }

// Example 2: Animating Card when scrolled into view
// <AnimateWrapper inView threshold={0.3} fade slide scale>
//   <Card>
//     <CardContent>
//       <Typography>This card fades, slides and scales in at 30% visibility</Typography>
//     </CardContent>
//   </Card>
// </AnimateWrapper>

// Example 3: Creating a section with staggered children
// <AnimateWrapper stagger={0.1}>
//   <Typography>First item</Typography>
//   <Typography>Second item appears 0.1s later</Typography>
//   <Typography>Third item appears 0.2s later</Typography>
// </AnimateWrapper>

// Example 4: Adding hover and tap effects to MUI elements
// <AnimateWrapper hover tap scale>
//   <Button variant="contained">Interactive Button</Button>
// </AnimateWrapper>
//
// <AnimateWrapper fade scale hover>
//   <Paper elevation={3}>
//     <Typography>Content inside animated Paper</Typography>
//   </Paper>
// </AnimateWrapper>

// Example 5: Creating an animated grid layout
// <Grid container spacing={2}>
//   {items.map((item, index) => (
//     <Grid item xs={12} sm={6} md={4} key={item.id}>
//       <AnimateWrapper 
//         fade 
//         slide 
//         delay={index * 0.1} 
//         hover
//       >
//         <Card>
//           <CardContent>{item.content}</CardContent>
//         </Card>
//       </AnimateWrapper>
//     </Grid>
//   ))}
// </Grid>

// Example 6: Working with plain HTML elements
// <AnimateWrapper fade slide>
//   <div className="custom-container">
//     <h2>This works with regular HTML too</h2>
//     <p>Not just MUI components</p>
//   </div>
// </AnimateWrapper>

// Example 7: Using with custom components
// <AnimateWrapper fade scale hover>
//   <MyCustomComponent prop1="value" prop2={123} />
// </AnimateWrapper>

